home *** CD-ROM | disk | FTP | other *** search
/ Atari Mega Archive 2 / Atari Mega Archive CD - Volume 2.iso / minix / up1510b.tgz / up1510b / src / commands / tar.c < prev    next >
C/C++ Source or Header  |  1990-07-23  |  22KB  |  907 lines

  1. /* tar - tape archiver            Author: Michiel Huisjes */
  2.  
  3. /* Usage: tar [cxt][vo][F][f] tapefile [files]
  4.  *
  5.  * attempt to make tar to conform to POSIX 1003.1
  6.  * disclaimer: based on an old (1986) POSIX draft.
  7.  * Klamer Schutte, 20/9/89
  8.  *
  9.  * Changes:
  10.  *  Changed to handle the original minix-tar format.    KS 22/9/89
  11.  *  Changed to handle BSD4.3 tar format.        KS 22/9/89
  12.  *  Conform to current umask if not super-user.        KS 22/9/89
  13.  *  Update usage message to show f option        KS 22/9/89
  14.  *
  15.  *
  16.  * 1)    tar will back itself up, should check archive inode num(&dev) and
  17.     then check the target inode number. In verbose mode, issue
  18.     warning, in all cases ignore target.
  19.     marks@mgse        Mon Sep 25 10:38:58 CDT 1989
  20.       added global varaibles, made changes to main() and add_file();
  21.     maks@mgse Mon Sep 25 12:09:20 CDT 1989
  22.  
  23.    2)    tar will not notice that a file has changed size while it was being
  24.     backed up. should issue warning.
  25.     marks@mgse        Mon Sep 25 10:38:58 CDT 1989
  26.  
  27.    3)    the 'f' option was not documented in usage[].
  28.     marks@mgse        Mon Sep 25 12:03:20 CDT 1989
  29.       changed both usage[] defines. Why are there two (one is commented out)?
  30.       ( deleted by me (was done twice) -- KS, 2/10/89 )
  31.  *
  32.  *  changed stat on tar_fd to an fstat                KS 2/10/89
  33.  *  deleted mkfifo() code -- belongs in libc.a            KS 2/10/89
  34.  *  made ar_dev default to -1 : an illegal device        KS 2/10/89
  35.  *  made impossible to chown if normal user            KS 2/10/89
  36.  *  if names in owner fields not known use numirical values    KS 2/10/89
  37.  *  creat with mask 666 -- use umask if to liberal        KS 2/10/89
  38.  *  allow to make directories as ../directory            KS 2/10/89
  39.  *  allow tmagic field to end with a space (instead of \0)    KS 2/10/89
  40.  *  correct usage of tmagic field                 KS 3/10/89
  41.  *  made mkdir() to return a value if directory == "."      KS 3/10/89
  42.  *  made lint complains less (On a BSD 4.3 system)        KS 3/10/89
  43.  *  use of directory(3) routines                KS 3/10/89
  44.  *  deleted use of d_namlen selector of struct dirent        KS 18/10/89
  45.  *
  46.  * Bugs:
  47.  *  verbose mode is not reporting consistent
  48.  *  code needs cleanup
  49.  *  prefix field is not used
  50.  *  timestamp of a directory will not be correct if there are files to be
  51.  *  unpacked in the directory
  52.  *    (add you favorite bug here (or two (or three (or ...))))
  53. */
  54.  
  55. #include <sys/types.h>
  56. #include <sys/stat.h>
  57. #include <fcntl.h>
  58. #include <pwd.h>
  59. #include <grp.h>
  60. #include <tar.h>
  61. #include <stdio.h>        /* need NULL */
  62.  
  63. #define    POSIX_COMP        /* POSIX compatible */
  64. #define DIRECT_3        /* use directory(3) routines */
  65.  
  66. #ifdef DIRECT_3
  67. #ifndef BSD
  68. /* To all minix users: i am sorry, developed this piece of code on a
  69.  * BSD system. KS 18/10/89 */
  70. #include <dirent.h>
  71. #define    direct    dirent        /* stupid BSD non-POSIX compatible name! */
  72. #else                /* BSD */
  73. #include <sys/dir.h>
  74. #include <dir.h>
  75. #endif                /* BSD */
  76. #endif                /* DIRECT_3 */
  77.  
  78. #ifdef S_IFIFO
  79. #define    HAVE_FIFO        /* have incorporated Simon Pooles' changes */
  80. #endif
  81.  
  82. typedef char BOOL;
  83. #define TRUE    1
  84. #define FALSE    0
  85.  
  86. #define HEADER_SIZE    TBLOCK
  87. #define NAME_SIZE    NAMSIZ
  88. /* #define BLOCK_BOUNDARY     20 -- not in POSIX ! */
  89.  
  90. typedef union hblock HEADER;
  91.  
  92. /* Make the MINIX member names overlap to the POSIX names */
  93. #define    m_name        name
  94. #define m_mode        mode
  95. #define m_uid        uid
  96. #define m_gid        gid
  97. #define m_size        size
  98. #define    m_time        mtime
  99. #define    m_checksum    chksum
  100. #define    m_linked    typeflag
  101. #define    m_link        linkname
  102. #define    hdr_block    dummy
  103. #define    m        header
  104. #define    member        dbuf
  105.  
  106. #if 0                /* original structure -- see tar.h for new
  107.              * structure */
  108. typedef union {
  109.   char hdr_block[HEADER_SIZE];
  110.   struct m {
  111.     char m_name[NAME_SIZE];
  112.     char m_mode[8];
  113.     char m_uid[8];
  114.     char m_gid[8];
  115.     char m_size[12];
  116.     char m_time[12];
  117.     char m_checksum[8];
  118.     char m_linked;
  119.     char m_link[NAME_SIZE];
  120.   } member;
  121. } HEADER;
  122.  
  123. #endif
  124.  
  125. /* Structure used to note links */
  126. struct link {
  127.   ino_t ino;
  128.   dev_t dev;
  129.   char name[NAMSIZ];
  130.   struct link *next;
  131. } *link_top = NULL;
  132.  
  133. HEADER header;
  134.  
  135. #define INT_TYPE    (sizeof(header.member.m_uid))
  136. #define LONG_TYPE    (sizeof(header.member.m_size))
  137.  
  138. #define MKDIR        "/bin/mkdir"
  139.  
  140. #define NIL_HEADER    ((HEADER *) 0)
  141. #define NIL_PTR        ((char *) 0)
  142. #define BLOCK_SIZE    TBLOCK
  143.  
  144. #define flush()        print(NIL_PTR)
  145.  
  146. BOOL show_fl, creat_fl, ext_fl;
  147.  
  148. int tar_fd;
  149. /* Char usage[] = "Usage: tar [cxt] tarfile [files]."; */
  150. char usage[] = "Usage: tar [cxt][vo][F][f] tarfile [files].";
  151. char io_buffer[BLOCK_SIZE];
  152. char path[NAME_SIZE];
  153. char pathname[NAME_SIZE];
  154. int force_flag = 0;
  155. #ifdef ORIGINAL_DEFAULTS
  156. int chown_flag = 1;
  157. int verbose_flag = 1;
  158. #else
  159. int chown_flag = 0;
  160. int verbose_flag = 0;
  161. #endif
  162.  
  163. /* Make sure we don't tar ourselves. marks@mgse Mon Sep 25 12:06:28 CDT 1989 */
  164. ino_t ar_inode;            /* archive inode number     */
  165. dev_t ar_dev;            /* archive device number */
  166.  
  167. int total_blocks;
  168. int u_mask;            /* one's complement of current umask */
  169.  
  170. long convert();
  171.  
  172. #define block_size()    (int) ((convert(header.member.m_size, LONG_TYPE) \
  173.     + (long) BLOCK_SIZE - 1) / (long) BLOCK_SIZE)
  174.  
  175. error(s1, s2)
  176. char *s1, *s2;
  177. {
  178.   string_print(NIL_PTR, "%s %s\n", s1, s2 ? s2 : "");
  179.   flush();
  180.   exit(1);
  181. }
  182.  
  183. BOOL get_header();
  184.  
  185. main(argc, argv)
  186. int argc;
  187. register char *argv[];
  188. {
  189.   register char *mem_name;
  190.   register char *ptr;
  191.   struct stat st;
  192.   int i;
  193.  
  194.   if (argc < 3) error(usage, NIL_PTR);
  195.  
  196.   for (ptr = argv[1]; *ptr; ptr++) {
  197.     switch (*ptr) {
  198.         case 'c':    creat_fl = TRUE;    break;
  199.         case 'x':    ext_fl = TRUE;    break;
  200.         case 't':    show_fl = TRUE;    break;
  201.         case 'v':        /* verbose output  -Dal */
  202.         verbose_flag = !verbose_flag;
  203.         break;
  204.         case 'o':        /* chown/chgrp files  -Dal */
  205.         chown_flag = TRUE;
  206.         break;
  207.         case 'F':        /* IGNORE ERRORS  -Dal */
  208.         force_flag = TRUE;
  209.         break;
  210.         case 'f':        /* standard U*IX usage -KS */
  211.         break;
  212.         default:    error(usage, NIL_PTR);
  213.     }
  214.   }
  215.  
  216.   if (creat_fl + ext_fl + show_fl != 1) error(usage, NIL_PTR);
  217.  
  218.   if (strcmp(argv[2], "-") == 0)/* only - means stdin/stdout - KS */
  219.     tar_fd = creat_fl ? 1 : 0;    /* '-' means used
  220.                      * stdin/stdout  -Dal */
  221.   else
  222.     tar_fd = creat_fl ? creat(argv[2], 0666) : open(argv[2], O_RDONLY);
  223.  
  224.   if (tar_fd < 0) error("Cannot open ", argv[2]);
  225.  
  226.   if (geteuid()) {        /* check if super-user */
  227.     int save_umask;
  228.     save_umask = umask(0);
  229.     u_mask = ~save_umask;
  230.     umask(save_umask);
  231.     chown_flag = TRUE;    /* normal user can't chown */
  232.   } else
  233.     u_mask = 0777;        /* don't restrict if 'privileged utiliy' */
  234.  
  235.   ar_dev = -1;            /* impossible device nr */
  236.   if (creat_fl) {
  237.     if (tar_fd > 1 && fstat(tar_fd, &st) < 0)
  238.         error("Can't stat ", argv[2]);    /* will never be here,
  239.                          * right? */
  240.     else {            /* get archive inode & device     */
  241.         ar_inode = st.st_ino;    /* save files inode     */
  242.         ar_dev = st.st_dev;    /* save files device     */
  243.     }            /* marks@mgse Mon Sep 25 11:30:45 CDT 1989 */
  244.  
  245.     for (i = 3; i < argc; i++) {
  246.         add_file(argv[i]);
  247.         path[0] = '\0';
  248.     }
  249.     adjust_boundary();
  250.   } else if (ext_fl) {
  251.     /* extraction code moved here from tarfile() MSP */
  252.     while (get_header()) {
  253.         mem_name = header.member.m_name;
  254.         if (is_dir(mem_name)) {
  255.             for (ptr = mem_name; *ptr; ptr++);
  256.             *(ptr - 1) = '\0';
  257.             header.dbuf.typeflag = '5';
  258.         }
  259.         for (i = 3; i < argc; i++)
  260.             if (!strncmp(argv[i], mem_name, strlen(argv[i])))
  261.                 break;
  262.         if (argc == 3 || (i < argc)) {
  263.             extract(mem_name);
  264.         } else
  265.             if (header.dbuf.typeflag == '0' ||
  266.                 header.dbuf.typeflag == 0 ||
  267.                 header.dbuf.typeflag == ' ')
  268.                 skip_entry();
  269.         flush();
  270.       }
  271.   } else
  272.     tarfile();    /* tarfile() justs prints info. now MSP */
  273.  
  274.   flush();
  275.   exit(0);
  276. }
  277.  
  278. BOOL get_header()
  279. {
  280.   register int check;
  281.  
  282.   mread(tar_fd, (char *) &header, sizeof(header));
  283.   if (header.member.m_name[0] == '\0') return FALSE;
  284.  
  285.   if (force_flag)        /* skip checksum verification  -Dal */
  286.     return TRUE;
  287.  
  288.   check = (int) convert(header.member.m_checksum, INT_TYPE);
  289.  
  290.   if (check != checksum()) error("Tar: header checksum error.", NIL_PTR);
  291.  
  292.   return TRUE;
  293. }
  294.  
  295. /* tarfile() just lists info about archive now; as of the t flag. */
  296. /* Extraction has been moved into main() as that needs access to argv[] */
  297.  
  298. tarfile()
  299. {
  300.   register char *ptr;
  301.   register char *mem_name;
  302.  
  303.   while (get_header()) {
  304.     mem_name = header.member.m_name;
  305.     string_print(NIL_PTR, "%s%s", mem_name,
  306.              (verbose_flag ? " " : "\n"));
  307.     switch (header.dbuf.typeflag) {
  308.         case '1':
  309.         verb_print("linke